#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/sem.h>

#define N		20
#define	FLNAME	"/tmp/out1.txt"
#define BUFSIZE	32

static int semid;

static void P(void);
static void V(void);
static void rw_file(void);

int main(void)
{
    FILE *fp = NULL;
    int i;
    pid_t pid;

    // 信号量集中只有一个成员 数组中一个元素
    semid = semget(IPC_PRIVATE, 1, IPC_CREAT | IPC_EXCL | 0600);
    
    if(-1 == semid) {
        perror("semgget()");
        exit(1);
    }

    // 初始化信号的个数, 将数组中下标为0的成员初始化为1
    semctl(semid, 0, SETVAL, 1);

    fp = fopen(FLNAME, "w");
    
    if (NULL == fp) {
        perror("fopen()");
        exit(1);
    }

    fputs("0", fp);
    fclose(fp);

    for (i = 0; i < N; i++) {
        pid = fork();
    
        if (-1 == pid) {
            perror("fork()");
            exit(1);
        }

        if (0 == pid) {
            rw_file();	
            exit(0);
        }
    }

    for (i = 0; i < N; i++)
        wait(NULL);

    semctl(semid, 0, IPC_RMID, NULL);

    return 0;
}

static void rw_file(void)
{
    FILE *fp = NULL;
    char buf[BUFSIZE] = {};

    // sleep(1);

    fp = fopen(FLNAME, "r+"); 
    if (NULL == fp) {
        perror("fopen()");
        return;
    }
    /*
       多进程之间竞争
       */
    // 取信号
    P();
    fgets(buf, BUFSIZE, fp);
    // sleep(1);
    rewind(fp);
    fprintf(fp, "%d", atoi(buf) + 1);
    fclose(fp);
    // 还信号
    V();
}

static void P(void)
{
    struct sembuf sop;

    sop.sem_num = 0;// 数组下标
    sop.sem_op = -1; // 取走一个信号
    sop.sem_flg = 0; // 没有特殊要求
    
    if (-1 == semop(semid, &sop, 1)) {
        perror("semop()");
        return;
    }
}

static void V(void)
{
    struct sembuf sop;

    sop.sem_num = 0;// 数组下标
    sop.sem_op = 1; // 还一个信号
    sop.sem_flg = 0; // 没有特殊要求
    
    if (-1 == semop(semid, &sop, 1)) {
        perror("semop()");
        return;
    }
}

